﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Threading;
using UnityEngine;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using Spine.Unity;
using UnityEngine.UI;

/// <summary>
/// 拓展方法
/// </summary>
public static class CommonUtil 
{

    #region 自定义
    /// <summary>
    /// 下个等级是否存在新词条
    /// </summary>
    /// <param name="level"></param>
    /// <returns></returns>
    public static  bool IsNextLevelHaveNewEntry(this int level)
    {
        return level == 6 || level == 9 || level == 12;
    }




    #endregion

    #region 比对

    /// <summary>
    /// 判断两个值是否相等（在指定的误差范围内）
    /// </summary>
    /// <param name="v">被比较值</param>
    /// <param name="value">比较值</param>
    /// <param name="precision">误差范围</param>
    /// <returns></returns>
    public static bool Compare(this int v, int value, float precision = float.Epsilon)
    {
        return Mathf.Abs(v - value) <= precision;
    } 
    
    /// <summary>
    /// 判断两个值是否相等（在指定的误差范围内）
    /// </summary>
    /// <param name="v">被比较值</param>
    /// <param name="value">比较值</param>
    /// <param name="precision">误差范围</param>
    /// <returns></returns>
    public static bool Compare(this float v, float value, float precision = float.Epsilon)
    {
        return Mathf.Abs(v - value) <= precision;
    }

    /// <summary>
    /// 判断两个值是否相等（在指定的误差范围内）
    /// </summary>
    /// <param name="v">被比较值</param>
    /// <param name="value">比较值</param>
    /// <param name="precision">误差范围</param>
    /// <returns></returns>
    public static bool Compare(this float v, double value, float precision = float.Epsilon)
    {
        return Mathf.Abs((int)(v - value)) <= precision;
    }

    /// <summary>
    /// 判断两个值是否相等（在指定的误差范围内）
    /// </summary>
    /// <param name="v">被比较值</param>
    /// <param name="value">比较值</param>
    /// <param name="precision">误差范围</param>
    /// <returns></returns>
    public static bool Compare(this float v, int value, float precision = float.Epsilon)
    {
        return Mathf.Abs(v - value) <= precision;
    }

    /// <summary>
    /// 判断两个值是否相等（在指定的误差范围内）
    /// </summary>
    /// <param name="v">被比较值</param>
    /// <param name="value">比较值</param>
    /// <param name="precision">误差范围</param>
    /// <returns></returns>
    public static bool Compare(this float v, long value, float precision = float.Epsilon)
    {
        return Mathf.Abs(v - value) <= precision;
    }

    /// <summary>
    /// 判断两个值是否相等（在指定的误差范围内）
    /// </summary>
    /// <param name="v">被比较值</param>
    /// <param name="value">比较值</param>
    /// <param name="precision">误差范围</param>
    /// <returns></returns>
    public static bool Compare(this double v, double value, double precision = double.Epsilon)
    {
        return Mathf.Abs((int)(v - value)) <= precision;
    }


    #endregion


    #region 字典方法

    /// <summary>
    /// 找到当前字典的最小空槽
    /// </summary>
    /// <param name="dict"></param>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    /// <returns></returns>
    public static int FindMinEmptySlot<TKey, TValue>(this Dictionary<TKey, TValue> dict,int MAXCOUNT=1000)
    {
        // 假设字典的键是连续的整数并且从0开始
        for (var i = 0; i < MAXCOUNT; i++)
        {
            if (!dict.ContainsKey((TKey)Convert.ChangeType(i, typeof(TKey))))
            {
                return i;
            }
        }
        Debug.LogError("所有位置都被占用");
        // 如果所有位置都被占用，返回-1或其他适当的值
        return -1;
    }

    
    /// <summary>
    /// 删除指定条件的元素
    /// </summary>
    /// <param name="dict"></param>
    /// <param name="predicate"></param>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    /// <returns></returns>
    public static bool RemoveIf<TKey, TValue>(this Dictionary<TKey, TValue> dict, Func<TValue, bool> predicate)
    {
        var keyToRemove = default(TKey);
        var found = false;
        
        foreach (var kvp in dict.Where(kvp => predicate(kvp.Value)))
        {
            keyToRemove = kvp.Key;
            found = true;
            break;
        }

        if (!found) return false;
        dict.Remove(keyToRemove);
        return true;

    }
    
    /// <summary>
    /// 查找指定条件的元素
    /// </summary>
    /// <param name="dict"></param>
    /// <param name="predicate"></param>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    /// <returns></returns>
    public static TKey? FindIf<TKey, TValue>(this Dictionary<TKey, TValue> dict, Func<TValue, bool> predicate) where TKey : struct
    {
        foreach (var kvp in dict.Where(kvp => predicate(kvp.Value)))
        {
            return kvp.Key;
        }

        return null;
    }
    
    
    
    
    /// <summary>
    /// 增加字典元素
    /// </summary>
    /// <param name="dict">字典</param>
    /// <param name="value">要添加的值</param>
    /// <param name="maxRange">字典的最大范围</param>
    /// <typeparam name="TKey">键的类型</typeparam>
    /// <typeparam name="TValue">值的类型</typeparam>
    /// <returns>是否成功添加</returns>
    public static bool AddValueWithMinEmpty<TKey, TValue>(this Dictionary<TKey, TValue> dict, TValue value,
        int maxRange)
    {
        var emptySlot = dict.FindMinEmptySlot(maxRange);
        if (emptySlot == -1)
        {
            //Debug.LogWarning("找不到空槽，添加失败");
            return false;
        }
        dict.Add((TKey)Convert.ChangeType(emptySlot, typeof(TKey)), value);
        return true;
    }
    #endregion

    public static int ReturnNumDigit(this int v)
    {
        return (v / 10).ToString().Length;
    }


    public static int ReturnNumDigit(this long v)
    {
        return (v / 10000000).ToString().Length;
    }


    public static bool IsNull(this Component gameObject) => System.Object.ReferenceEquals(gameObject, null);
    public static bool IsNotNull(this Component gameObject) => !System.Object.ReferenceEquals(gameObject, null);

    public static float ToFloat(this string str)
    {
        float res = 0;
        if (!string.IsNullOrEmpty(str))
        {
            bool suc = float.TryParse(str, out res);
            if (!suc)
                Debug.LogError("转为float失败：" + str);
        }
        return res;
    }  
    public static double ToDouble(this string str)
    {
        double res = 0;
        if (!string.IsNullOrEmpty(str))
        {
            bool suc = double.TryParse(str, out res);
            if (!suc)
                Debug.LogError("转为double失败：" + str);
        }
        return res;
    }
    public static Int32 ToInt32(this string str)
    {
        Int32 res = 0;
        if (!string.IsNullOrEmpty(str))
        {
            try
            {
                res = Convert.ToInt32(str);
            }
            catch(Exception)
            {
              Debug.LogError("转为int32失败：" + str);
            }
        }
        return res;
    } 
    /// <summary>
    /// 取绝对值
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static Int32 ToUInt32(this string str)
    {
        Int32 res = 0;
        if (!string.IsNullOrEmpty(str))
        {
            try
            {
                res = Convert.ToInt32(str);
            }
            catch(Exception)
            {
              Debug.LogError("转为int32失败：" + str);
            }
        }
        return Mathf.Abs(res);
    }
    /// <summary>
    /// 可能会丢失精度
    /// </summary>
    /// <param name="f"></param>
    /// <returns></returns>
    public static Int32 ToInt32(this float f)
    {
        return (int)f;
    } 
    
    /// <summary>
    /// 可能会丢失精度
    /// </summary>
    /// <param name="f"></param>
    /// <returns></returns>
    public static Int32 ToInt32KeepDecimal(this float f)
    {
        return System.Convert.ToInt32(f);
    }
    /// <summary>
    /// 取绝对值
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static Int32 ToUInt32(this int f)
    {
        return Mathf.Abs(f);
    }

    public static Int64 ToInt64(this string str)
    {
        Int64 res = 0;
        if (!string.IsNullOrEmpty(str))
        {
            try
            {
                res = Convert.ToInt64(str);
            }
            catch (Exception)
            {
                Debug.LogError("转为int64失败：" + str);
            }
        }
        return res;
    }

    public static Int32 ToInt32(this Enum eme)
    {
        Int32 res = 0;
        if (!string.IsNullOrEmpty(eme.ToString()))
        {
            try
            {
                res = Convert.ToInt32(eme);
            }
            catch (Exception)
            {
                Debug.LogError("转为int32失败：" + eme);
            }
        }
        return res;
    }
    
    public static int ToInt(this Enum eme)
    {
        int res = 0;
        if (!string.IsNullOrEmpty(eme.ToString()))
        {
            try
            {
                res = Convert.ToInt32(eme);
            }
            catch (Exception)
            {
                Debug.LogError("转为int失败：" + eme);
            }
        }
        return res;
    }

    public static Color ReturnColorWithRGBA(this string rgba)
    {
        Color color;
        ColorUtility.TryParseHtmlString(rgba, out color);
        return color;
    }

    /// <summary>
    /// 返回中文基数单位
    /// </summary>
    /// <param name="count"></param>
    /// <param name="dividend">默认显示万</param>
    /// /// <param name="keepDecimalNum">默认保留1位小数</param>
    /// <returns></returns>
    public static string ReturnChineseNum(this int count,float dividend=10000,int keepDecimalNum=1)
    {
        string str = "";
        switch (dividend)
        {
            case 100:
                str = "百";
                break;  
            case 1000:
                str = "千";
                break;  
            case 10000:
                str = "万";
                break;
            case 1000000:
                str = "百万";
                break; 
            case 10000000:
                str = "千万";
                break; 
            case 100000000:
                str = "千万";
                break;
            default:
                break;
        }
        

        if (count/ dividend<1)
        {
            //小于万
            return count.ToString();
        }
        float num = KeepDecimal(count / dividend, keepDecimalNum);


        return num.ToString()+str;
    }

    /// <summary>
    /// 返回中文基数（万、亿）
    /// </summary>
    /// <param name="number"></param>
    /// <returns></returns>
    public static string ReturnChineseNum(this int number)
    {
        if (number < 10000)
        {
            return number.ToString();
        }
        else if (number < 100000000)
        {
            double result = number / 10000.0;
            return $"{result:F1}万";
        }
        else
        {
            double result = number / 100000000.0;
            return $"{result:F1}亿";
        }
    }
    
    /// <summary>
    /// 返回中文大基数（万、亿）
    /// </summary>
    /// <param name="number"></param>
    /// <returns></returns>
    public static string ReturnChineseBigNum(this long number)
    {
        if (number < 10000)
        {
            return number.ToString();
        }
        else if (number < 100000000)
        {
            double result = number / 10000.0;
            return $"{result:F1}万";
        }
        else if (number < 1000000000000)
        {
            double result = number / 100000000.0;
            return $"{result:F1}亿";
        }
        else
        {
            double result = number / 1000000000000.0;
            return $"{result:F1}万亿";
        }
    }

    #region 乱序
    /// <summary>
    /// 乱序
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="bag"></param>
    /// <returns></returns>
    public static List<T> Outoforder<T>(this List<T> bag)
    {

        System.Random randomNum = new System.Random();
        int index = 0;
        T temp;
        for (int i = 0; i < bag.Count; i++)
        {

            index = randomNum.Next(0, bag.Count - 1);
            if (index != i)
            {

                temp = bag[i];
                bag[i] = bag[index];
                bag[index] = temp;
            }
        }
        return bag;
    }
    #endregion

/*    /// <summary>
    /// 获得小数位（默认获取后一位）
    /// </summary>
    /// <param name="num"></param>
    /// <param name="index"></param>
    /// <returns></returns>
    public static float GetDecimalNum(this float num,int index = 1)
    {
        string indexStr = "0";
        if (index >= 1)
        {
            indexStr += ".";
            for (int i = 0; i < index; i++)
            {
                indexStr += "0";
            }
        }
    }*/
/// <summary>
/// 保留小数,四舍五入（默认保留一位）
/// </summary>
/// <param name="num"></param>
/// <param name="index"></param>
/// <returns></returns>
public static float KeepDecimalRounding(this float num,int index=1)
    {
        string indexStr = "0";
        if (index>=1)
        {
            indexStr += ".";
            for (int i = 0; i < index; i++)
            {
                indexStr += "0";
            }
        }
/*        decimal c= decimal.Parse(num.ToString(indexStr));
        return (float)c;
        Debug.Log(indexStr);*/
        return float.Parse(num.ToString(indexStr));
    }

    /// <summary>
    /// 保留小数（默认保留一位）
    /// </summary>
    /// <param name="num"></param>
    /// <param name="index"></param>
    /// <returns></returns>
    public static float KeepDecimal(this float num, int index = 1)
    {
        int range = 1;
        if (index>0)
        {
            for (int i = 0; i < index; i++)
            {
                range *= 10;
            }
        }
        int numInterger = (int)(num * range);
        num = numInterger / (float)range;
        return num;
    }
    
    public static UInt64 ToUInt64(this string str)
    {
        UInt64 res = 0;
        if (!string.IsNullOrEmpty(str))
        {
            try
            {
                res = Convert.ToUInt64(str);
            }
            catch (Exception)
            {
                Debug.LogError("转为uint64失败：" + str);
            }
        }
        return res;
    }
    /// <summary>
    /// 1，0
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static bool ToBool(this string str)
    {
        if (string.IsNullOrEmpty(str))
            return false;
        if(str == "1")
            return true;
        if (str == "0")
            return false;
        return false;

    }  

    public static Vector3 ToVector3(this string str)
    {
        if (string.IsNullOrEmpty(str))
            return Vector3.zero;
        string[] tails = str.Split(',');
        Vector3 res;
        res.x = tails[0].ToFloat();
        res.y = tails[1].ToFloat();
        res.z = tails[2].ToFloat();
        return res;
    }
    public static Vector2 ToVector2(this string str)
    {
        if (string.IsNullOrEmpty(str))
            return Vector2.zero;
        string[] tails = str.Split(',');
        Vector2 res;
        res.x = tails[0].ToFloat();
        res.y = tails[1].ToFloat();
        return res;
    }
    public static void Log(this object obj)
    {
        Debug.Log(obj.ToString());
    }
    public static void LogWarning(this object obj)
    {
        Debug.LogWarning(obj.ToString());
    }
    public static void LogError(this object obj)
    {
        Debug.LogError(obj.ToString());
    }

    /// <summary>
    /// 该字符串是否是中文
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static bool IsNoneChinese(this string str)
    {
        bool result = false;
        for (int i = 0; i < str.Length; i++)
        {
            Regex reg = new Regex(@"[\u4e00-\u9fa5]");
            if (!reg.IsMatch(str[i].ToString()))
            {
                result = true;
                break;
            }
        }
        return result;
    }

    public static bool IsNotNull(this string str)
    {
        return  !string.IsNullOrEmpty(str);
    }


    /// <summary>
    /// 数字变化
    /// </summary>
    /// <param name="initNum">初始数字</param>
    /// <param name="showNum">显示的数字(结果)</param>
    /// <param name="targetNum">目标数字</param>
    /// <param name="v">Linear：时间    EaseOut：比例值</param>
    /// <param name="changeType">变化类型</param>
    public static double NumberChange(double initNum, double showNum, double targetNum, float v, ChangeType changeType = ChangeType.Linear)
    {
        switch (changeType)
        {
            case ChangeType.Linear:
                showNum += (targetNum - initNum) * Time.deltaTime / v;
                if (showNum >= targetNum)
                {
                    showNum = targetNum;
                }
                return showNum;
            case ChangeType.EaseIn:
                return showNum;
            case ChangeType.EaseOut:
                showNum += (targetNum - showNum) * Time.deltaTime / v;
                return showNum;
            default:
                return 0;
        }
    }

    /// <summary>
    /// 数值检查（大于100小于0的进行控制）
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static float CheckValue(float value)
    {
        if (value >= 100)
            return 100;

        if (value <= 0)
            return 0;

        return value;
    }


    public static Task ToTask(Action<TaskCompletionSource<object>> act, CancellationToken token = default)
    {
        return ToTask<object>(act, token);
    }

    public static Task<T> ToTask<T>(Action<TaskCompletionSource<T>> act, CancellationToken token = default)
    {
        var handler = new TaskCompletionSource<T>();

        if (token.IsCancellationRequested)
        {
            handler.TrySetCanceled();
            return handler.Task;
        }
        else
        {
            token.Register(() => handler.TrySetCanceled());
            try
            {
                //执行传入的操作
                act?.Invoke(handler);
                return handler.Task;
            }
            catch (Exception)
            {

                throw;
            }
        }
    }

    /// <summary>
    /// 获取ip
    /// </summary>
    /// <returns></returns>
    public static string GetIP()
    {
        NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
        foreach (NetworkInterface adater in adapters)
        {
            if (adater.Supports(NetworkInterfaceComponent.IPv4))
            {
                UnicastIPAddressInformationCollection UniCast = adater.GetIPProperties().UnicastAddresses;
                if (UniCast.Count > 0)
                {
                    foreach (UnicastIPAddressInformation uni in UniCast)
                    {
                        if (uni.Address.AddressFamily == AddressFamily.InterNetwork)
                        {
                            Debug.Log(uni.Address.ToString());
                            return uni.Address.ToString();
                        }
                    }
                }
            }
        }
        return null;
    }

    /// <summary>
    /// 刷新组件
    /// </summary>
    /// <param name="rectTransform"></param>
    public static void RefreashRectTransform(this RectTransform rectTransform)
    {
        LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform);
    }

    /// <summary>
    /// UI隐藏
    /// </summary>
    /// <param name="obj"></param>
    public static void Hidden(this GameObject obj)
    {
        if (obj.GetComponent<CanvasGroup>()==null)
        {
            obj.AddComponent<CanvasGroup>();
        }
        obj.GetComponent<CanvasGroup>().alpha = 0;
        obj.GetComponent<CanvasGroup>().interactable = false;
        obj.GetComponent<CanvasGroup>().blocksRaycasts = false;
    } 
    
 
    /// <summary>
    /// UI显示
    /// </summary>
    /// <param name="obj"></param>
    public static void Display(this GameObject obj)
    {
        if (obj.GetComponent<CanvasGroup>()==null)
        {
            obj.AddComponent<CanvasGroup>();
        }
        obj.GetComponent<CanvasGroup>().alpha = 1;
        obj.GetComponent<CanvasGroup>().interactable= true;
        obj.GetComponent<CanvasGroup>().blocksRaycasts= true;
    }

    /// <summary>
    /// UI隐藏
    /// </summary>
    /// <param name="obj"></param>
    public static void Hidden(this Transform trans)
    {
        trans.position = new Vector3(10000, 10000, 10000);
    }

    /// <summary>
    /// UI显示
    /// </summary>
    /// <param name="obj"></param>
    public static void Display(this Transform trans, Vector3 position = default)
    {
        //Debug.Log(position);
        trans.localPosition = position;
    }



    // 将 Sprite 转换为 Texture2D
    public static Texture2D SpriteToTexture2D(this Sprite sprite)
    {
        if (sprite == null)
        {
            Debug.LogError("Sprite is null. Cannot convert to Texture2D.");
            return null;
        }

        Texture2D texture = new Texture2D((int)sprite.rect.width, (int)sprite.rect.height);
        texture.SetPixels(sprite.texture.GetPixels((int)sprite.textureRect.x, (int)sprite.textureRect.y,
            (int)sprite.textureRect.width, (int)sprite.textureRect.height));
        texture.Apply();

        return texture;
    }




}






/// <summary>
/// 变化速度的类型
/// </summary>
public enum ChangeType
{
    Linear,//线性
    EaseIn,//先慢后快
    EaseOut,//先快后慢
}

